/*Copyright 2011 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
#limitations under the License.*/

ClientGameEngineClass = GameEngineClass.extend({
	gSocket: null,
	newMapPos: {x:0,y:0},

	init: function () {
	this.parent();
	},
	//-----------------------------
	setup: function () 
	{
		Logger.log ("ClientGameEngineClass.setup called");
		this.parent();
	
		//bind commands to keys
		gInputEngine.bind(gInputEngine.KEY.W, 'move-up');
		gInputEngine.bind(gInputEngine.KEY.S, 'move-down');
		gInputEngine.bind(gInputEngine.KEY.A, 'move-left');
		gInputEngine.bind(gInputEngine.KEY.D, 'move-right');
	
		gInputEngine.bind(gInputEngine.KEY.UP_ARROW, 'option_disable');
		gInputEngine.bind(gInputEngine.KEY.DOWN_ARROW, 'option_enable');
		gInputEngine.bind(gInputEngine.KEY.LEFT_ARROW, 'cycle_left');
		gInputEngine.bind(gInputEngine.KEY.RIGHT_ARROW, 'cycle_right');
	
		gInputEngine.bind(gInputEngine.KEY.MOUSE1, 'fire0-mouse');
		gInputEngine.bind(gInputEngine.KEY.SHIFT, 'fire1-instead-of-0');
		gInputEngine.bind(gInputEngine.KEY.MOUSE2, 'fire1-mouse');
		gInputEngine.bind(gInputEngine.KEY.SPACE, 'fire0');
		gInputEngine.bind(gInputEngine.KEY.M, 'select');
		// Misc Commands

	},
	//-----------------------------
	update: function () {
		this.parent();
	
		//var inputEngine = gInputEngine;  //z: FIND OUT REASON
	
		// ensure the gMap viewRectangle matches the canvas size
		if (gRenderEngine.canvas.width != this.gMap.viewRect.w) {
		  this.gMap.viewRect.w = gRenderEngine.canvas.width;
		}
		if (gRenderEngine.canvas.height != this.gMap.viewRect.h) {
		  this.gMap.viewRect.h = gRenderEngine.canvas.height;
		}
	
		// don't continue update: if the client has no player or the player is dead
		if (!this.gPlayer0 || this.gPlayer0.isDead) {
		  return;
		}
	
		//logic
		var pInput = {
		  x: 0,
		  y: 0,
		  // implement banking up/down later
		  moving: false,
		  fire0: false,
		  fire1: false,
		  fire2: false,
		  select: false
		};
		var move_dir = new Vec2(0, 0);
		if (gInputEngine.state('move-up'))
		  move_dir.y -= 1;
		if (gInputEngine.state('move-down'))
		  move_dir.y += 1;
		if (gInputEngine.state('move-left'))
		  move_dir.x -= 1;
		if (gInputEngine.state('move-right'))
		  move_dir.x += 1;
	
			// only if player moves:
		if (move_dir.LengthSquared()) {
		  pInput.moving = true;
		  move_dir.Normalize();
		  move_dir.Multiply(this.gPlayer0.moveSpeed);
		  pInput.x += move_dir.x;
		  pInput.y += move_dir.y;
		} else {
		  pInput.moving = false;
		  pInput.x = 0;
		  pInput.y = 0;
		}
	
		var dPX = gRenderEngine.getScreenPosition(this.gPlayer0.pos).x;
		var dPY = gRenderEngine.getScreenPosition(this.gPlayer0.pos).y;
		/*
		if (gInputEngine.state('fire0-mouse') )
		  pInput.fire0 = true;
		else
		  pInput.fire1 = true;
		
	
		if (gInputEngine.state('fire1-instead-of-0'))
		  pInput.fire1 = true;
		else
		  pInput.fire0 = true;
		*/
		if (gInputEngine.state('fire0')) {
		  pInput.fire0 = true;
		}
	
		if (gInputEngine.state('fire1')) {
		  pInput.fire1 = true;
		}
		if (gInputEngine.state('fire2')) {
		  pInput.fire2 = true;
		}
		if (gInputEngine.state('select')) {
		  pInput.select = true;
		}
	
		// Record and send out inputs
		this.gPlayer0.pInput = pInput;
		//this.gPlayer0.sendUpdates(); z: KEEP as comments to understand flow
		//this.gSocket.sendq(); z: KEEP
	
		//recenter our map bounds based upon the player's centered y-position and scrollPoint x-position
		this.newMapPos.x = gLevel.scrollPoint.pos.x - (this.gMap.viewRect.w * 0.5);
		this.newMapPos.y = Math.max(0, 
									Math.min (this.gMap.pixelSize.y-this.gMap.viewRect.h,
											  this.gPlayer0.pos.y - (this.gMap.viewRect.h * 0.5)));

		if (this.gPlayer0.stateChange) {
			gGuiEngine.needsDraw = true;
			this.gPlayer0.stateChange = false;
		} // Z: NB this is not optimal ofcourse
		gGuiEngine.draw();
	},
	//-----------------------------
	run: function() 
	{
		this.parent();
	
		var fractionOfNextPhysicsUpdate = this.timeSincePhysicsUpdate / Constants.PHYSICS_LOOP_HZ;
		this.update();
		//gGuiEngine.draw();
		this.draw(fractionOfNextPhysicsUpdate);
		gInputEngine.clearPressed();
	},

	//-----------------------------
	draw: function (fractionOfNextPhysicsUpdate) 
	{

		// Alpha-beta filter on camera
		this.gMap.viewRect.x = parseInt(alphaBeta(this.gMap.viewRect.x, this.newMapPos.x, 0.8));
		this.gMap.viewRect.y = parseInt(alphaBeta(this.gMap.viewRect.y, this.newMapPos.y, 0.8));
	
		// Draw map.
		this.gMap.draw(null);
	
		// Bucket entities by zIndex
		var fudgeVariance = 128;
		var zIndex_array = [];
		var entities_bucketed_by_zIndex = {}
		this.entities.forEach(function(entity) {
			//don't draw entities that are off screen
			if(	entity.pos.x >= gGameEngine.gMap.viewRect.x-fudgeVariance && entity.pos.x < gGameEngine.gMap.viewRect.x+gGameEngine.gMap.viewRect.w+fudgeVariance &&
				entity.pos.y >= gGameEngine.gMap.viewRect.y-fudgeVariance && entity.pos.y < gGameEngine.gMap.viewRect.y+gGameEngine.gMap.viewRect.h+fudgeVariance)
			{				
				if (zIndex_array.indexOf(entity.zIndex) === -1) 
				{
					zIndex_array.push(entity.zIndex);
					entities_bucketed_by_zIndex[entity.zIndex] = [];
				}
				entities_bucketed_by_zIndex[entity.zIndex].push(entity);
			}
		});
	
		// Draw entities sorted by zIndex
		zIndex_array.sort(function (a,b) {return a - b;});
		zIndex_array.forEach(function(zIndex) {
		  entities_bucketed_by_zIndex[zIndex].forEach(function(entity) {
					entity.draw(fractionOfNextPhysicsUpdate);
		  });
		});
	},
	//-----------------------------
	requestRespawn: function () {

	Logger.log("requesting respawn for " + this.gPlayer0.name);

	/*	gGameEngine.gSocket.send_respawn({
				from: this.gPlayer0.name,
				wep0: gWeapons_DB.weapons[gGuiEngine.pendingWeaponSwapIdxs[0]].logicClass,
				wep1: gWeapons_DB.weapons[gGuiEngine.pendingWeaponSwapIdxs[1]].logicClass,
				wep2: gWeapons_DB.weapons[gGuiEngine.pendingWeaponSwapIdxs[2]].logicClass,
	          });
	*/             
	},
	//-----------------------------
	playWorldSound:function(soundURL,x,y)
	{
		if(this.gPlayer0 == null) return;
		var gMap = gGameEngine.gMap;
		//fade out volume based upon distance to me
		var viewSize = Math.max(gMap.viewRect.w,gMap.viewRect.h) * 0.5;
		var oCenter = this.gPlayer0.pos;
		var dx = Math.abs(oCenter.x - x);
		var dy = Math.abs(oCenter.y - y);
		var distToObserver = Math.sqrt(dx*dx + dy*dy);
		var normDist = distToObserver / viewSize;
		if(normDist > 1) normDist = 1;
		if(normDist <0) return;//dont' play
			
		var volume = 1.0 - normDist;
			
		//volume = distance to center of current player
		var sound = gSM.loadAsync(soundURL, function(sObj) 
		{
			gSM.playSound(sObj.path,{looping:false, volume:volume});	
			// gSM.playsObj.play(false);
		});
	},
	//-----------------------------		
	preloadComplete:false,
	preloadSheets:null,
	preloadAssets:function (maps)
	{
		//go load images first
		var assets = new Array();
		gGameEngine.preloadSheets = new Array();
		gGameEngine.preloadSheets.push("sotee_sprites");
		gGameEngine.preloadSheets.push("sotee_effects");	
		/*sounds
		assets.push("./sound/bg_game.ogg");
		assets.push("./sound/bounce0.ogg");
		assets.push("./sound/energy_pickup.ogg");
		assets.push("./sound/explode0.ogg");
		assets.push("./sound/grenade_shoot0.ogg");
		assets.push("./sound/item_pickup0.ogg");
		assets.push("./sound/machine_shoot0.ogg");
		assets.push("./sound/quad_pickup.ogg");
		assets.push("./sound/rocket_shoot0.ogg");
		assets.push("./sound/shield_activate.ogg");
		assets.push("./sound/shotgun_shoot0.ogg");
		assets.push("./sound/spawn0.ogg");
		assets.push("./sound/sword_activate.ogg");
		*/
		Logger.log (assets);
		loadAssets(assets, function()
		{			
		  // Code to read in Texturepacker.com generated spritesheets
		  gGameEngine.preloads = 0;
		  for (var i=0; i<gGameEngine.preloadSheets.length;i++) 
		  {
			gGameEngine.preloads++;
			xhrGet("img/"+gGameEngine.preloadSheets[i]+".json", false, (function(i){
				return function(data){
					var obj = JSON.parse(data.response);
						
					var sheet = new SpriteSheetClass();
					gSpriteSheets[gGameEngine.preloadSheets[i]] = sheet;
					sheet.load("img/"+obj.meta.image);
						
					for (var key=0; key<obj.frames.length; key++)
					{
						var val = obj.frames[key];
						var cx=-val.frame.w * 0.5;
						var cy=-val.frame.h * 0.5;
						
						if(val.trimmed)
						{
							cx = val.spriteSourceSize.x - (val.sourceSize.w * 0.5);
							cy = val.spriteSourceSize.y - (val.sourceSize.h * 0.5);
							
						}
						
						sheet.defSprite(val.filename, val.frame.x, val.frame.y, val.frame.w, val.frame.h, cx, cy);
					}
			
					gGameEngine.preloads -=1;
					gGameEngine.preloadComplete = (gGameEngine.preloads <= 0);
				}})(i));
			};
		});
	},
	//-----------------------------
	colorTintSprite_fcn:function(colorStr,callbackFcn,settings)
	{
		if(callbackFcn == null)	return;
		
		gGameEngine.colorTintCanvasContext.clearRect ( 0 , 0 , 128, 128);
			callbackFcn(gGameEngine.colorTintCanvasContext,settings);
		
		var context =gGameEngine.colorTintCanvasContext2;
		context.clearRect ( 0 , 0 , 128, 128);
		 context.drawImage(gGameEngine.colorTintCanvas, 0, 0);
		var g = context.globalCompositeOperation;
		context.globalCompositeOperation = 'source-in'; 
		context.fillStyle=colorStr;
		context.fillRect(0,0,128,128);         
		context.globalCompositeOperation = 'darker';   
		context.drawImage(gGameEngine.colorTintCanvas, 0, 0);
		context.globalCompositeOperation = g;
	},
	calcSpriteRotAngle:function(origFace,desiredRotationAngle)
	{
		var firstAngle = 0;
		if(origFace == 0)	//top
			firstAngle = 0;
			
	}
});

// Override the parent's singleton
gGameEngine = new ClientGameEngineClass();

